package org.gjy.m8.thread;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 宫静雨
 * @version 1.0
 * @since 2023-12-13 14:46:43
 */
public class AbcTest {
    private static final Logger log = LoggerFactory.getLogger(AbcTest.class);

    private static final ReentrantLock LOCK = new ReentrantLock();
    private static final Condition c1 = LOCK.newCondition();
    private static final Condition c2 = LOCK.newCondition();
    private static final Condition c3 = LOCK.newCondition();
    private static final AtomicInteger flag = new AtomicInteger(1);

    public void c1() {
        LOCK.lock();
        try {
            log.info("c1");
            if (flag.get() != 1) {
                c1.await();
            }
            flag.set(2);
            c2.signal();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            LOCK.unlock();
        }
    }

    public void c2() {
        LOCK.lock();
        try {
            log.info("c2");
            if (flag.get() != 2) {
                c2.await();
            }
            flag.set(3);
            c3.signal();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            LOCK.unlock();
        }
    }

    public void c3() {
        LOCK.lock();
        try {
            log.info("c3");
            if (flag.get() != 3) {
                c3.await();
            }
            flag.set(1);
            c1.signal();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            LOCK.unlock();
        }
    }

    @Test
    public void test1() throws InterruptedException {
        ExecutorService pool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            pool.execute(this::c1);
            pool.execute(this::c2);
            pool.execute(this::c3);
        }
        TimeUnit.SECONDS.sleep(1);
        pool.shutdown();
    }
}
